package org.xxpay.service.impl;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.xxpay.core.common.constant.MchConstant;
import org.xxpay.core.common.util.StrUtil;
import org.xxpay.core.common.util.XXPayUtil;
import org.xxpay.core.entity.*;
import org.xxpay.core.service.IMchInfoService;
import org.xxpay.core.service.ISysAttachmentService;
import org.xxpay.core.service.ISysConfigService;
import org.xxpay.service.common.annotation.DataSourceSwitch;
import org.xxpay.service.common.enumm.DataSourceType;
import org.xxpay.service.dao.mapper.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

/**
 * @author: dingzhiwei
 * @date: 17/9/8
 * @description:
 */
@Service
public class MchInfoServiceImpl implements IMchInfoService {

    @Autowired
    private MchInfoMapper mchInfoMapper;

    @Autowired
    private MchAccountMapper mchAccountMapper;

    @Autowired
    private ISysConfigService sysConfigService;

    @Autowired
    private ISysAttachmentService sysAttachmentService;

    @Autowired
    private MchAccountHistoryMapper mchAccountHistoryMapper;
    @Autowired
    private MchAgentpayPassageMapper mchAgentpayPassageMapper;
    @Autowired
    private MchAgentpayRecordMapper mchAgentpayRecordMapper;
    @Autowired
    private MchAppMapper mchAppMapper;
    @Autowired
    private SettBankAccountMapper settBankAccountMapper;
    @Autowired
    private MchBillMapper mchBillMapper;
    @Autowired
    private MchNotifyMapper mchNotifyMapper;
    @Autowired
    private MchPayPassageMapper mchPayPassageMapper;
    @Autowired
    private MchQrCodeMapper mchQrCodeMapper;
    @Autowired
    private MchSettBatchRecordMapper mchSettBatchRecordMapper;
    @Autowired
    private MchSettDailyCollectMapper mchSettDailyCollectMapper;
    @Autowired
    private MchTradeOrderMapper mchTradeOrderMapper;
    @Autowired
    private PayOrderMapper payOrderMapper;
    @Autowired
    private RefundOrderMapper refundOrderMapper;
    @Autowired
    private SettRecordMapper settRecordMapper;
    @Autowired
    private TransOrderMapper transOrderMapper;


    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public long add(MchInfo mchInfo, List<SysAttachment> attachments) {
        // 插入商户基本信息
        int updateRow = mchInfoMapper.insertSelective(mchInfo);
        if(updateRow != 1) return 0;

        long mchId = mchInfo.getMchId();

        // 插入商户账户信息
        MchAccount mchAccount = new MchAccount();
        mchAccount.setMchId(mchId);
        mchAccount.setName(mchInfo.getName());
        mchAccount.setType(MchConstant.MCH_TYPE_PLATFORM);  // 目前只支持平台账户
        mchAccount.setBalance(BigDecimal.ZERO.longValue());
        mchAccount.setSecurityMoney(BigDecimal.ZERO.longValue());
        mchAccount.setSettAmount(BigDecimal.ZERO.longValue());
        mchAccount.setUnBalance(BigDecimal.ZERO.longValue());
        mchAccount.setTodayExpend(BigDecimal.ZERO.longValue());
        mchAccount.setTodayIncome(BigDecimal.ZERO.longValue());
        mchAccount.setTotalExpend(BigDecimal.ZERO.longValue());
        mchAccount.setTotalIncome(BigDecimal.ZERO.longValue());
        mchAccount.setFrozenMoney(BigDecimal.ZERO.longValue());
        mchAccount.setAgentpayBalance(BigDecimal.ZERO.longValue());
        mchAccount.setUnAgentpayBalance(BigDecimal.ZERO.longValue());
        mchAccount.setAgentpayFrozenMoney(BigDecimal.ZERO.longValue());
        mchAccount.setSafeKey(XXPayUtil.genAccountSafeKey(mchAccount));
        updateRow = mchAccountMapper.insertSelective(mchAccount);

        //更新失败
        if(updateRow <= 0 ){
            return 0;
        }
        //不需要新增附件信息  直接返回mchId
        if( attachments == null || attachments.isEmpty()){
            return mchId;
        }

        //替换商户ID， 和图片路径地址。
        for(SysAttachment attachment : attachments){
            attachment.setInfoId(mchId);
            attachment.setInfoType(MchConstant.SETT_INFO_TYPE_MCH);
        }
        updateRow = sysAttachmentService.addOrUpdate(attachments);

        if(updateRow <= 0){
            return 0;
        }
        return mchId;
    }

    @Override
    @Transactional
    public long register(MchInfo record, List<SysAttachment> attachments) {

        int updateRow = mchInfoMapper.insertSelective(record);
        if(updateRow <= 0 ){  //更新失败
            return 0;
        }
        long mchId = record.getMchId();
        //不需要新增附件信息  直接返回mchId
        if( attachments == null || attachments.isEmpty()){
            return mchId;
        }

        //替换商户ID， 和图片路径地址。
        for(SysAttachment attachment : attachments){
            attachment.setInfoId(mchId);
            attachment.setInfoType(MchConstant.SETT_INFO_TYPE_MCH);
        }
        updateRow = sysAttachmentService.addOrUpdate(attachments);

        if(updateRow <= 0){
            return 0;
        }
        return mchId;
    }

    @Override
    public int update(MchInfo record) {
        return mchInfoMapper.updateByPrimaryKeySelective(record);
    }

    @Override
    public MchInfo find(MchInfo mchInfo) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, mchInfo);
        List<MchInfo> mchInfoList = mchInfoMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(mchInfoList)) return null;
        return mchInfoList.get(0);
    }

    @Override
    public MchInfo findByMchId(Long mchId) {
        return mchInfoMapper.selectByPrimaryKey(mchId);
    }

    @Override
    public MchInfo findByLoginName(String loginName) {
        if(StringUtils.isBlank(loginName)) return null;
        MchInfo mchInfo;
        if(StrUtil.checkEmail(loginName)) {
            mchInfo = findByEmail(loginName);
            if(mchInfo != null) return mchInfo;
        }
        if(StrUtil.checkMobileNumber(loginName)) {
            mchInfo = findByMobile(Long.parseLong(loginName));
            if(mchInfo != null) return mchInfo;
        }
        if(NumberUtils.isDigits(loginName)) {
            mchInfo = findByMchId(Long.parseLong(loginName));
            if(mchInfo != null) return mchInfo;
        }
        mchInfo = findByUserName(loginName);
        return mchInfo;
    }

    @Override
    public MchInfo findByMobile(Long mobile) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        criteria.andMobileEqualTo(mobile);
        List<MchInfo> mchInfoList = mchInfoMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(mchInfoList)) return null;
        return mchInfoList.get(0);
    }

    @Override
    public MchInfo findByEmail(String email) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        criteria.andEmailEqualTo(email);
        List<MchInfo> mchInfoList = mchInfoMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(mchInfoList)) return null;
        return mchInfoList.get(0);
    }

    @Override
    public MchInfo findByTag(String tag) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        criteria.andTagEqualTo(tag);
        List<MchInfo> mchInfoList = mchInfoMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(mchInfoList)) return null;
        return mchInfoList.get(0);
    }

    @Override
    public MchInfo findByUserName(String userName) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        criteria.andUserNameEqualTo(userName);
        List<MchInfo> mchInfoList = mchInfoMapper.selectByExample(example);
        if(CollectionUtils.isEmpty(mchInfoList)) return null;
        return mchInfoList.get(0);
    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public int auditOk(Long mchInd) {
        // 修改商户状态
        MchInfo updateMchInfo = new MchInfo();
        updateMchInfo.setStatus(MchConstant.STATUS_OK);
        updateMchInfo.setRole(MchConstant.MCH_ROLE_NORMAL);
        updateMchInfo.setPrivateKey(RandomStringUtils.randomAlphanumeric(128).toUpperCase());   // 设置商户私钥
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        criteria.andMchIdEqualTo(mchInd);
        List<Byte> status = new LinkedList<>();
        status.add(MchConstant.STATUS_AUDIT_ING);
        status.add(MchConstant.STATUS_AUDIT_NOT);
        criteria.andStatusIn(status);
        int count = mchInfoMapper.updateByExampleSelective(updateMchInfo, example);
        if(count != 1) return 0;
        MchInfo mchInfo = findByMchId(mchInd);
        // 插入商户账户信息
        MchAccount mchAccount = new MchAccount();
        mchAccount.setMchId(mchInfo.getMchId());
        mchAccount.setName(mchInfo.getName());
        mchAccount.setType(mchInfo.getType());
        mchAccount.setBalance(BigDecimal.ZERO.longValue());
        mchAccount.setSecurityMoney(BigDecimal.ZERO.longValue());
        mchAccount.setSettAmount(BigDecimal.ZERO.longValue());
        mchAccount.setUnBalance(BigDecimal.ZERO.longValue());
        mchAccount.setTodayExpend(BigDecimal.ZERO.longValue());
        mchAccount.setTodayIncome(BigDecimal.ZERO.longValue());
        mchAccount.setTotalExpend(BigDecimal.ZERO.longValue());
        mchAccount.setTotalIncome(BigDecimal.ZERO.longValue());
        mchAccount.setFrozenMoney(BigDecimal.ZERO.longValue());
        mchAccount.setAgentpayBalance(BigDecimal.ZERO.longValue());
        mchAccount.setUnAgentpayBalance(BigDecimal.ZERO.longValue());
        mchAccount.setAgentpayFrozenMoney(BigDecimal.ZERO.longValue());
        mchAccount.setSafeKey(XXPayUtil.genAccountSafeKey(mchAccount));
        count = mchAccountMapper.insertSelective(mchAccount);
        return count;
    }

    @Override
    public int auditNot(Long mchInd) {
        MchInfo mchInfo = new MchInfo();
        mchInfo.setStatus(MchConstant.STATUS_AUDIT_NOT);
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        criteria.andMchIdEqualTo(mchInd);
        criteria.andStatusEqualTo(MchConstant.STATUS_AUDIT_ING);
        int count = mchInfoMapper.updateByExampleSelective(mchInfo, example);
        return count;
    }

    @Override
    public List<MchInfo> select(int offset, int limit, MchInfo mchInfo) {
        MchInfoExample example = new MchInfoExample();
        example.setOrderByClause("createTime DESC");
        example.setOffset(offset);
        example.setLimit(limit);
        MchInfoExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, mchInfo);
        return mchInfoMapper.selectByExample(example);
    }

    @Override
    public List<MchInfo> select4Audit(int offset, int limit, MchInfo mchInfo) {
        MchInfoExample example = new MchInfoExample();
        example.setOrderByClause("createTime DESC");
        example.setOffset(offset);
        example.setLimit(limit);
        MchInfoExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, mchInfo);
        List<Byte> status = new LinkedList<>();
        status.add(MchConstant.STATUS_AUDIT_NOT);
        status.add(MchConstant.STATUS_AUDIT_ING);
        criteria.andStatusIn(status);
        return mchInfoMapper.selectByExample(example);
    }

    @Override
    public List<MchInfo> select4Normal(int offset, int limit, MchInfo mchInfo) {
        MchInfoExample example = new MchInfoExample();
        example.setOrderByClause("createTime DESC");
        example.setOffset(offset);
        example.setLimit(limit);
        MchInfoExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, mchInfo);
        List<Byte> status = new LinkedList<>();
        status.add(MchConstant.STATUS_STOP);
        status.add(MchConstant.STATUS_OK);
        criteria.andStatusIn(status);
        return mchInfoMapper.selectByExample(example);
    }

    @Override
    public Integer count(MchInfo mchInfo) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, mchInfo);
        return mchInfoMapper.countByExample(example);
    }

    @Override
    public Integer count4Audit(MchInfo mchInfo) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, mchInfo);
        List<Byte> status = new LinkedList<>();
        status.add(MchConstant.STATUS_AUDIT_NOT);
        status.add(MchConstant.STATUS_AUDIT_ING);
        criteria.andStatusIn(status);
        return mchInfoMapper.countByExample(example);
    }

    @Override
    public Integer count4Normal(MchInfo mchInfo) {
        MchInfoExample example = new MchInfoExample();
        MchInfoExample.Criteria criteria = example.createCriteria();
        setCriteria(criteria, mchInfo);
        List<Byte> status = new LinkedList<>();
        status.add(MchConstant.STATUS_STOP);
        status.add(MchConstant.STATUS_OK);
        criteria.andStatusIn(status);
        return mchInfoMapper.countByExample(example);
    }

    @Override
    @DataSourceSwitch(DataSourceType.SLAVE)
    public Map count4Mch() {
        Map param = new HashMap<>();
        return mchInfoMapper.count4Mch(param);
    }

    @Override
    public MchInfo reBuildMchInfoSettConfig(MchInfo info) {
        // 继承系统,按系统配置设置结算属性
        if(info.getSettConfigMode() == 1) {
            JSONObject settObj = sysConfigService.getSysConfigObj("sett");
            info.setDrawFlag(settObj.getByte("drawFlag"));
            info.setAllowDrawWeekDay(settObj.getString("allowDrawWeekDay"));
            info.setDrawDayStartTime(settObj.getString("drawDayStartTime"));
            info.setDrawDayEndTime(settObj.getString("drawDayEndTime"));
            info.setDayDrawTimes(settObj.getInteger("dayDrawTimes"));
            info.setDrawMaxDayAmount(settObj.getLong("drawMaxDayAmount"));
            info.setMaxDrawAmount(settObj.getLong("maxDrawAmount"));
            info.setMinDrawAmount(settObj.getLong("minDrawAmount"));
            info.setFeeType(settObj.getByte("feeType"));
            info.setFeeRate(settObj.getBigDecimal("feeRate"));
            info.setFeeLevel(settObj.getString("feeLevel"));
            info.setDrawFeeLimit(settObj.getLong("drawFeeLimit"));
            info.setSettMode(settObj.getByte("settMode"));
        }
        return info;
    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public int updateMchInfoAndAttachment(MchInfo info, List<SysAttachment> attachments) {

        this.update(info);

        //先删除后新增
        sysAttachmentService.delByInfoId(MchConstant.SETT_INFO_TYPE_MCH, info.getMchId());

        // 更新商户账户名称
        MchAccount updateMchAccount = new MchAccount();
        updateMchAccount.setMchId(info.getMchId());
        updateMchAccount.setName(info.getName());
        mchAccountMapper.updateByPrimaryKeySelective(updateMchAccount);

        //不需要新增附件信息  直接返回mchId
        if( attachments == null || attachments.isEmpty()){
            return 1;
        }

        //替换商户ID， 和图片路径地址。
        for(SysAttachment attachment : attachments){
            attachment.setInfoId(info.getMchId());
            attachment.setInfoType(MchConstant.SETT_INFO_TYPE_MCH);
        }
        sysAttachmentService.addOrUpdate(attachments);

        return 1;
    }

    @Override
    public List<MchInfo> selectByExample2(int offset, int limit, MchInfo mchInfo) {
        Map param = new HashMap();
        param.put("offset", offset);
        param.put("limit", limit);
        if(mchInfo.getMchId() != null) param.put("mchId", mchInfo.getMchId());
        return mchInfoMapper.selectByExample2(param);
    }

    @Override
    @Transactional(transactionManager = "transactionManager", rollbackFor = Exception.class)
    public int relationDelete(List<Long> ids){

        int result = 0;

        // [1]. 删除 订单/统计 相关信息

        //商户[代付记录表]记录
        MchAgentpayRecordExample mchAgentpayRecordExample = new MchAgentpayRecordExample();
        mchAgentpayRecordExample.createCriteria().andMchIdIn(ids);
        result += mchAgentpayRecordMapper.deleteByExample(mchAgentpayRecordExample);

        //商户[转账订单]记录
        TransOrderExample transOrderExample = new TransOrderExample();
        transOrderExample.createCriteria().andMchIdIn(ids);
        transOrderMapper.deleteByExample(transOrderExample);

        //商户[商户交易表]记录
        MchTradeOrderExample mchTradeOrderExample = new MchTradeOrderExample();
        mchTradeOrderExample.createCriteria().andMchIdIn(ids);
        result += mchTradeOrderMapper.deleteByExample(mchTradeOrderExample);

        //商户[支付订单表]记录
        PayOrderExample payOrderExample = new PayOrderExample();
        payOrderExample.createCriteria().andMchIdIn(ids);
        result += payOrderMapper.deleteByExample(payOrderExample);

        //商户[商户通知表]记录
        MchNotifyExample mchNotifyExample = new MchNotifyExample();
        mchNotifyExample.createCriteria().andMchIdIn(ids);
        result += mchNotifyMapper.deleteByExample(mchNotifyExample);

        //商户[退款订单表]记录
        RefundOrderExample refundOrderExample = new RefundOrderExample();
        refundOrderExample.createCriteria().andMchIdIn(ids);
        result += refundOrderMapper.deleteByExample(refundOrderExample);

        //商户[结算记录表]记录
        SettRecordExample settRecordExample = new SettRecordExample();
        settRecordExample.createCriteria().andInfoIdIn(ids).andInfoTypeEqualTo(MchConstant.SETT_INFO_TYPE_MCH);
        result += settRecordMapper.deleteByExample(settRecordExample);

        //商户[商户对账单]记录
        MchBillExample mchBillExample = new MchBillExample();
        mchBillExample.createCriteria().andMchIdIn(ids);
        result += mchBillMapper.deleteByExample(mchBillExample);

        //商户[批量结算明细表]记录
        MchSettBatchRecordExample mchSettBatchRecordExample = new MchSettBatchRecordExample();
        mchSettBatchRecordExample.createCriteria().andMchIdIn(ids);
        result += mchSettBatchRecordMapper.deleteByExample(mchSettBatchRecordExample);

        //商户[商户每日结算汇总]记录
        MchSettDailyCollectExample mchSettDailyCollectExample = new MchSettDailyCollectExample();
        mchSettDailyCollectExample.createCriteria().andMchIdIn(ids);
        result += mchSettDailyCollectMapper.deleteByExample(mchSettDailyCollectExample);

        //商户[资金流水]记录
        MchAccountHistoryExample mchAccountHistoryExample = new MchAccountHistoryExample();
        mchAccountHistoryExample.createCriteria().andMchIdIn(ids);
        result += mchAccountHistoryMapper.deleteByExample(mchAccountHistoryExample);

        // [2]. 删除商户配置相关记录

        //商户[商户统一扫码配置]记录
        MchQrCodeExample mchQrCodeExample = new MchQrCodeExample();
        mchQrCodeExample.createCriteria().andMchIdIn(ids);
        result += mchQrCodeMapper.deleteByExample(mchQrCodeExample);

        //商户[商户银行账号表]记录
        SettBankAccountExample settBankAccountExample = new SettBankAccountExample();
        settBankAccountExample.createCriteria().andInfoIdIn(ids).andInfoTypeEqualTo(MchConstant.ACCOUNT_STATUS_MCH);
        result += settBankAccountMapper.deleteByExample(settBankAccountExample);

        //商户[代付通道表]记录
        MchAgentpayPassageExample mchAgentpayPassageExample = new MchAgentpayPassageExample();
        mchAgentpayPassageExample.createCriteria().andMchIdIn(ids);
        result += mchAgentpayPassageMapper.deleteByExample(mchAgentpayPassageExample);

        //商户[商户应用表]记录
        MchAppExample mchAppExample = new MchAppExample();
        mchAppExample.createCriteria().andMchIdIn(ids);
        result += mchAppMapper.deleteByExample(mchAppExample);

        //商户[商户支付通道表]记录
        MchPayPassageExample mchPayPassageExample = new MchPayPassageExample();
        mchPayPassageExample.createCriteria().andMchIdIn(ids);
        result += mchPayPassageMapper.deleteByExample(mchPayPassageExample);


        // [3]. 删除商户信息主表记录

        //商户[账户]记录
        MchAccountExample mchAccountExample = new MchAccountExample();
        mchAccountExample.createCriteria().andMchIdIn(ids);
        result += mchAccountMapper.deleteByExample(mchAccountExample);

        //商户[信息]记录
        MchInfoExample mchInfoExample = new MchInfoExample();
        mchInfoExample.createCriteria().andMchIdIn(ids);
        result += mchInfoMapper.deleteByExample(mchInfoExample);

        return result;
    }


    @Override
    public Map<String, String> selectNameMap() {
        MchInfoExample mchInfoExample = new MchInfoExample();
        List<MchInfo> mchInfoList = mchInfoMapper.selectByExample(mchInfoExample);
        Map<String, String> mchNameMap = new HashMap<>();
        if(CollectionUtils.isEmpty(mchInfoList)) return mchNameMap;
        for(MchInfo mchInfo : mchInfoList) {
            mchNameMap.put(mchInfo.getMchId()+"", mchInfo.getName());
        }
        return mchNameMap;
    }

    void setCriteria(MchInfoExample.Criteria criteria, MchInfo mchInfo) {
        if(mchInfo != null) {
            if(mchInfo.getMchId() != null) criteria.andMchIdEqualTo(mchInfo.getMchId());
            if(mchInfo.getType() != null && mchInfo.getType().byteValue() != -99) criteria.andTypeEqualTo(mchInfo.getType());
            if(mchInfo.getEmail() != null) criteria.andEmailEqualTo(mchInfo.getEmail());
            if(mchInfo.getMobile() != null) criteria.andMobileEqualTo(mchInfo.getMobile());
            if(mchInfo.getAgentId() != null) criteria.andAgentIdEqualTo(mchInfo.getAgentId());
            if(mchInfo.getStatus() != null) criteria.andStatusEqualTo(mchInfo.getStatus());
        }
    }

}
